Micron Document
baubs git

Node / mirrors / respira / commits / 0bd037b

Commit 0bd037b98a6791a0a4c245a4b399fbfca58c24fc


Parents : 8c0b893
Author : Jan-Henrik Bruhn <hi@jhbruhn.de>
Date : 2025-12-13T18:37:30+01:00

fix: Resolve pattern rendering and coordinate handling bugs

This commit addresses multiple critical issues in pattern rendering and coordinate handling:

1. Fixed Y-axis offset accumulation in penParser.ts
- Corrected sign extension logic for 16-bit signed coordinates
- Changed to interpret full 16-bit value as signed before shifting
- Prevents coordinate drift and offset accumulation

2. Fixed color assignment for tack stitches in patternConverter.worker.ts
- Added detection for small finishing stitches after COLOR_CHANGE commands
- Assigns tack stitches to correct (previous) color instead of new color
- Uses conservative pattern matching (< 1.0 unit, followed by JUMP)

3. Made jump stitches visible in pattern preview (KonvaComponents.tsx)
- Render jump stitches in thread color instead of gray
- Use dashed pattern [8, 4] to distinguish from regular stitches
- Set appropriate opacity (0.8 completed, 0.5 not completed)
- Fixed critical bug: include previous position in jump groups to create proper line segments

4. Updated konvaRenderers.ts for consistency
- Applied same jump stitch rendering logic
- Ensures consistent behavior across rendering methods

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

Changes

4 files changed, 88 insertions(+), 25 deletions(-)


Diff

diff --git a/src/components/KonvaComponents.tsx b/src/components/KonvaComponents.tsx
index 5d674ad..5c0e4ad 100644
--- a/src/components/KonvaComponents.tsx
+++ b/src/components/KonvaComponents.tsx
@@ -154,6 +154,9 @@ export const Stitches = memo(({ stitches, pesData, currentStitchIndex, showProgr
const groups: StitchGroup[] = [];
let currentGroup: StitchGroup | null = null;
+ let prevX = 0;
+ let prevY = 0;
+
for (let i = 0; i < stitches.length; i++) {
const stitch = stitches[i];
const [x, y, cmd, colorIndex] = stitch;
@@ -168,16 +171,30 @@ export const Stitches = memo(({ stitches, pesData, currentStitchIndex, showProgr
currentGroup.completed !== isCompleted ||
currentGroup.isJump !== isJump
) {
- currentGroup = {
- color,
- points: [x, y],
- completed: isCompleted,
- isJump,
- };
+ // For jump stitches, we need to create a line from previous position to current position
+ // So we include both the previous point and current point
+ if (isJump && i > 0) {
+ currentGroup = {
+ color,
+ points: [prevX, prevY, x, y],
+ completed: isCompleted,
+ isJump,
+ };
+ } else {
+ currentGroup = {
+ color,
+ points: [x, y],
+ completed: isCompleted,
+ isJump,
+ };
+ }
groups.push(currentGroup);
} else {
currentGroup.points.push(x, y);
}
+
+ prevX = x;
+ prevY = y;
}
return groups;
@@ -189,12 +206,12 @@ export const Stitches = memo(({ stitches, pesData, currentStitchIndex, showProgr
<Line
key={i}
points={group.points}
- stroke={group.isJump ? (group.completed ? '#cccccc' : '#e8e8e8') : group.color}
- strokeWidth={1.5}
+ stroke={group.color}
+ strokeWidth={group.isJump ? 1.5 : 1.5}
lineCap="round"
lineJoin="round"
- dash={group.isJump ? [3, 3] : undefined}
- opacity={group.isJump ? 1 : (showProgress && !group.completed ? 0.75 : 1.0)}
+ dash={group.isJump ? [8, 4] : undefined}
+ opacity={group.isJump ? (group.completed ? 0.8 : 0.5) : (showProgress && !group.completed ? 0.3 : 1.0)}
/>
))}
</Group>

diff --git a/src/utils/konvaRenderers.ts b/src/utils/konvaRenderers.ts
index 5484b2a..21ca8bc 100644
--- a/src/utils/konvaRenderers.ts
+++ b/src/utils/konvaRenderers.ts
@@ -159,14 +159,15 @@ export function renderStitches(
// Create Konva.Line for each group
groups.forEach((group) => {
if (group.isJump) {
- // Jump stitches - dashed gray lines
+ // Jump stitches - dashed lines in thread color
const line = new Konva.Line({
points: group.points,
- stroke: group.completed ? '#cccccc' : '#e8e8e8',
- strokeWidth: 1.5,
+ stroke: group.color,
+ strokeWidth: 1.0,
lineCap: 'round',
lineJoin: 'round',
- dash: [3, 3],
+ dash: [5, 5],
+ opacity: group.completed ? 0.6 : 0.25,
});
stitchesGroup.add(line);
} else {

diff --git a/src/utils/penParser.ts b/src/utils/penParser.ts
index 9c112e4..1610f3f 100644
--- a/src/utils/penParser.ts
+++ b/src/utils/penParser.ts
@@ -33,13 +33,18 @@ export function parsePenData(data: Uint8Array): PenData {
const yFlags = data[offset + 2] & 0x07;
// Decode coordinates (shift right by 3 to get actual position)
- // Using signed 16-bit interpretation
- let x = (xRaw >> 3);
- let y = (yRaw >> 3);
-
- // Convert to signed if needed
- if (x > 0x7FF) x = x - 0x2000;
- if (y > 0x7FF) y = y - 0x2000;
+ // The coordinates are stored as signed 16-bit values, left-shifted by 3
+ // We need to interpret them as signed before shifting
+
+ // Convert from unsigned 16-bit to signed 16-bit
+ let xSigned = xRaw;
+ let ySigned = yRaw;
+ if (xSigned > 0x7FFF) xSigned = xSigned - 0x10000;
+ if (ySigned > 0x7FFF) ySigned = ySigned - 0x10000;
+
+ // Now shift right by 3 (arithmetic shift, preserves sign)
+ let x = xSigned >> 3;
+ let y = ySigned >> 3;
const stitch: PenStitch = {
x,

diff --git a/src/workers/patternConverter.worker.ts b/src/workers/patternConverter.worker.ts
index 0878053..9d00271 100644
--- a/src/workers/patternConverter.worker.ts
+++ b/src/workers/patternConverter.worker.ts
@@ -210,15 +210,21 @@ def map_cmd(pystitch_cmd):
# Each stitch in pattern.stitches is [x, y, cmd]
# We need to assign color indices based on COLOR_CHANGE commands
# and filter out COLOR_CHANGE and STOP commands (they're not actual stitches)
+#
+# IMPORTANT: In PES files, COLOR_CHANGE commands can appear before finishing
+# stitches (tack/lock stitches) that semantically belong to the PREVIOUS color.
+# We need to detect this pattern and assign colors correctly.
stitches_with_colors = []
current_color = 0
+prev_color = 0
for i, stitch in enumerate(pattern.stitches):
x, y, cmd = stitch
- # Check for color change command - increment color but don't add stitch
+ # Check for color change command
if cmd == COLOR_CHANGE:
+ prev_color = current_color
current_color += 1
continue
@@ -230,10 +236,44 @@ for i, stitch in enumerate(pattern.stitches):
if cmd == END:
continue
- # Add actual stitch with color index and mapped command
- # Map PyStitch cmd values to our known JavaScript constant values
+ # Determine which color this stitch belongs to
+ # After a COLOR_CHANGE, check if this might be a finishing tack stitch
+ # belonging to the previous color rather than the new color
+ stitch_color = current_color
+
+ # If this is the first stitch after a color change (color just incremented)
+ # and it's a very small stitch before a JUMP, it's likely a tack stitch
+ if current_color != prev_color and len(stitches_with_colors) > 0:
+ last_x, last_y = stitches_with_colors[-1][0], stitches_with_colors[-1][1]
+ dx, dy = x - last_x, y - last_y
+ dist = (dx*dx + dy*dy)**0.5
+
+ # Check if this is a tiny stitch (< 1.0 unit - typical tack stitch)
+ # and if there's a JUMP coming soon
+ if dist < 1.0:
+ # Look ahead to see if there's a JUMP within next 10 stitches
+ has_jump_ahead = False
+ for j in range(i+1, min(i+11, len(pattern.stitches))):
+ next_stitch = pattern.stitches[j]
+ next_cmd = next_stitch[2]
+ if next_cmd == JUMP:
+ has_jump_ahead = True
+ break
+ elif next_cmd == STITCH:
+ # If we hit a regular stitch before a JUMP, this might be the new color
+ next_x, next_y = next_stitch[0], next_stitch[1]
+ next_dist = ((next_x - last_x)**2 + (next_y - last_y)**2)**0.5
+ # Only continue if following stitches are also tiny
+ if next_dist >= 1.0:
+ break
+
+ # If we found a jump ahead, this small stitch belongs to previous color
+ if has_jump_ahead:
+ stitch_color = prev_color
+
+ # Add actual stitch with assigned color index and mapped command
mapped_cmd = map_cmd(cmd)
- stitches_with_colors.append([x, y, mapped_cmd, current_color])
+ stitches_with_colors.append([x, y, mapped_cmd, stitch_color])
# Convert to JSON-serializable format
{

Served by rngit 1.4.2 - Generated in 0.09s